package com.ecarx.camera.worker.camera.dvr.impl;

import static com.ecarx.camera.constant.Constants.DEFAULT_LOOP_RECORD_DURATION;
import static com.ecarx.camera.constant.Constants.DEFAULT_LOOP_RECORD_RESOLUTION;
import static com.ecarx.camera.constant.Constants.INVALID_INDEX;
import static com.ecarx.camera.constant.Constants.INVALID_STR_VALUE;
import static com.ecarx.camera.constant.Constants.INVALID_VALUE;

import android.util.SparseIntArray;

import com.ecarx.camera.constant.Constants;
import com.ecarx.camera.utils.LogUtils;
import com.ecarx.camera.worker.camera.dvr.IDvrAPI;
import com.ecarx.camera.worker.car.FunctionValueWatcher;
import com.ecarx.camera.worker.car.ICarFunctionProxy;
import com.ecarx.camera.worker.car.aosp.AospCarManager;
import com.ecarx.xui.adaptapi.car.base.ICarFunction;
import com.ecarx.xui.adaptapi.car.dvr.IDvr;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;

/**
 * Dvr的CarPropertyManager实现（forR的AdaptAPI定义）
 */
public class DvrCarPropertyAPIForRImpl implements IDvrAPI, IDvrAPI.IDvrConfigAPI {

    private static final String TAG = "DvrCarPropertyAPIForRImpl";

    /**
     * 需要监测变化的functionIds
     */
    private static final int[] WATCHER_FUNCTION_IDS = new int[] {
            IDvr.DVR_FUNC_GENERAL_RECORDING_DURATION,
            IDvr.DVR_FUNC_GENERAL_RECORDING_MIC_MUTE,
            IDvr.DVR_FUNC_CAMERA_OPERATION_STATUS,
            IDvr.DVR_FUNC_CURRENT_STATUS,
            IDvr.DVR_FUNC_ERROR_STATUS,
            IDvr.DVR_FUNC_VIDEO_RESOLUTION,
            IDvr.DVR_FUNC_SDCARD_FORMAT_STATUS,
            IDvr.DVR_FUNC_FACTORY_RESET_STATUS,
            IDvr.DVR_FUNC_SDCARD_USED_PERCENTAGE,
            IDvr.DVR_FUNC_SDCARD_STATUS,
            IDvr.DVR_FUNC_EMMC_STATE,
            IDvr.DVR_FUNC_WAKEUP_ETHERNET
    };

    /**
     * 一般循环录像分辨率常量值与AdaptAPI中分辨率常量值的映射
     */
    private static final SparseIntArray RESOLUTION_MAP = new SparseIntArray();
    static {
        RESOLUTION_MAP.put(Constants.LoopRecordResolution.RESOLUTION_720P, IDvr.ResolutionType.RESOLUTION_720P_30FPS);
        RESOLUTION_MAP.put(Constants.LoopRecordResolution.RESOLUTION_1080P, IDvr.ResolutionType.RESOLUTION_1080P_30FPS);
    }

    /**
     * 一般循环录像时长常量值与AdaptAPI中时长常量值的映射
     */
    private static final SparseIntArray DURATION_MAP = new SparseIntArray();
    static {
        DURATION_MAP.put(Constants.LoopRecordDuration.DURATION_1_MIN, IDvr.RecordingDuration.ONE_MINUTES);
        DURATION_MAP.put(Constants.LoopRecordDuration.DURATION_3_MIN, IDvr.RecordingDuration.THREE_MINUTES);
        DURATION_MAP.put(Constants.LoopRecordDuration.DURATION_5_MIN, IDvr.RecordingDuration.FIVE_MINUTES);
    }

    /**
     * 静音常量与AdaptAPI中静音常量值的映射
     */
    private static final HashMap<Boolean, Integer> MIC_MUTE_MAP = new HashMap<>();
    static {
        // COMMON_VALUE_ON表明有声音；COMMON_VALUE_OFF表明无声音，静音
        MIC_MUTE_MAP.put(false, ICarFunction.COMMON_VALUE_ON);
        MIC_MUTE_MAP.put(true, ICarFunction.COMMON_VALUE_OFF);
    }

    private boolean mIsDvrGeneralRecording = false;
    private boolean mIsDvrEmergencyRecording = false;

    /**
     * 配置监听
     */
    private final ICarFunctionProxy.IFunctionValueWatcher mFunctionValueWatcher = new FunctionValueWatcher() {
        @Override
        public void onFunctionValueChanged(int functionId, int zone, int functionValue) {
            LogUtils.d(TAG, "onFunctionValueChanged, functionId:" + functionId + ", functionValue:" + functionValue);
            switch (functionId) {
                case IDvr.DVR_FUNC_GENERAL_RECORDING_DURATION:
                    int durationIndex = DURATION_MAP.indexOfValue(functionValue);
                    if (durationIndex != INVALID_INDEX) {
                        int duration = DURATION_MAP.keyAt(durationIndex);
                        LogUtils.d(TAG, "onFunctionValueChanged for DVR_FUNC_GENERAL_RECORDING_DURATION, functionValue:" + getFunctionDurationStr(functionValue) + ", value:" + duration);
                        for (IDvrAPI.IDvrConfigWatcher item : mDvrConfigWatchers) {
                            item.onDvrGeneralRecordDurationChanged(duration);
                        }
                    } else {
                        LogUtils.w(TAG, "onFunctionValueChanged for DVR_FUNC_GENERAL_RECORDING_DURATION, invalid functionValue:" + functionValue);
                    }
                    break;
                case IDvr.DVR_FUNC_GENERAL_RECORDING_MIC_MUTE:
                    boolean muteValue = (MIC_MUTE_MAP.get(true) == functionValue);
                    LogUtils.d(TAG, "onFunctionValueChanged for DVR_FUNC_GENERAL_RECORDING_MIC_MUTE, functionValue:" + functionValue + ", value:" + muteValue);
                    for (IDvrAPI.IDvrConfigWatcher item : mDvrConfigWatchers) {
                        item.onDvrGeneraRecordMicMuteChanged(muteValue);
                    }
                    break;
                case IDvr.DVR_FUNC_CAMERA_OPERATION_STATUS:
                    switch (functionValue) {
                        case IDvr.CameraOperationStatus.OPERATION_STATUS_UNKNOWN:
                            LogUtils.d(TAG, "onFunctionValueChanged for DVR_FUNC_CAMERA_OPERATION_STATUS, functionValue:OPERATION_STATUS_UNKNOWN");
                            for (IOperateResultsWatcher item : mOperateResultWatchers) {
                                item.onOperationUnknown();
                            }
                            break;
                        case IDvr.CameraOperationStatus.OPERATION_CAPTURE_PIC_PROGRESS:
                            LogUtils.d(TAG, "onFunctionValueChanged for DVR_FUNC_CAMERA_OPERATION_STATUS, functionValue:OPERATION_CAPTURE_PIC_PROGRESS");
                            for (IOperateResultsWatcher item : mOperateResultWatchers) {
                                item.onDvrCaptureInProgress();
                            }
                            break;
                        case IDvr.CameraOperationStatus.OPERATION_CAPTURE_PIC_SUCCEED:
                            LogUtils.d(TAG, "onFunctionValueChanged for DVR_FUNC_CAMERA_OPERATION_STATUS, functionValue:OPERATION_CAPTURE_PIC_SUCCEED");
                            for (IOperateResultsWatcher item : mOperateResultWatchers) {
                                item.onDvrCaptureSuccess();
                            }
                            break;
                        case IDvr.CameraOperationStatus.OPERATION_CAPTURE_PIC_FAILED:
                            LogUtils.d(TAG, "onFunctionValueChanged for DVR_FUNC_CAMERA_OPERATION_STATUS, functionValue:OPERATION_CAPTURE_PIC_FAILED");
                            for (IOperateResultsWatcher item : mOperateResultWatchers) {
                                item.onDvrCaptureFail();
                            }
                            break;
                        case IDvr.CameraOperationStatus.OPERATION_GENERAL_RECORDING_PROGRESS:
                            LogUtils.d(TAG, "onFunctionValueChanged for DVR_FUNC_CAMERA_OPERATION_STATUS, functionValue:OPERATION_GENERAL_RECORDING_PROGRESS");
                            for (IOperateResultsWatcher item : mOperateResultWatchers) {
                                item.onDvrGeneralRecordInProgress();
                            }
                            break;
                        case IDvr.CameraOperationStatus.OPERATION_GENERAL_RECORDING_SUCCEED:
                            LogUtils.d(TAG, "onFunctionValueChanged for DVR_FUNC_CAMERA_OPERATION_STATUS, functionValue:OPERATION_GENERAL_RECORDING_SUCCEED");
                            for (IOperateResultsWatcher item : mOperateResultWatchers) {
                                item.onDvrGeneralRecordSuccess();
                            }
                            break;
                        case IDvr.CameraOperationStatus.OPERATION_GENERAL_RECORDING_FAILED:
                            LogUtils.d(TAG, "onFunctionValueChanged for DVR_FUNC_CAMERA_OPERATION_STATUS, functionValue:OPERATION_GENERAL_RECORDING_FAILED");
                            for (IOperateResultsWatcher item : mOperateResultWatchers) {
                                item.onDvrGeneralRecordFail();
                            }
                            break;
                        case IDvr.CameraOperationStatus.OPERATION_PAUSE_RECORDING_PROGRESS:
                            LogUtils.d(TAG, "onFunctionValueChanged for DVR_FUNC_CAMERA_OPERATION_STATUS, functionValue:OPERATION_PAUSE_RECORDING_PROGRESS");
                            for (IOperateResultsWatcher item : mOperateResultWatchers) {
                                item.onDvrPauseGeneralRecordInProgress();
                            }
                            break;
                        case IDvr.CameraOperationStatus.OPERATION_PAUSE_RECORDING_SUCCEED:
                            LogUtils.d(TAG, "onFunctionValueChanged for DVR_FUNC_CAMERA_OPERATION_STATUS, functionValue:OPERATION_PAUSE_RECORDING_SUCCEED");
                            for (IOperateResultsWatcher item : mOperateResultWatchers) {
                                item.onDvrPauseGeneralRecordSuccess();
                            }
                            break;
                        case IDvr.CameraOperationStatus.OPERATION_PAUSE_RECORDING_FAILED:
                            LogUtils.d(TAG, "onFunctionValueChanged for DVR_FUNC_CAMERA_OPERATION_STATUS, functionValue:OPERATION_PAUSE_RECORDING_FAILED");
                            for (IOperateResultsWatcher item : mOperateResultWatchers) {
                                item.onDvrPauseGeneralRecordFail();
                            }
                            break;
                        case IDvr.CameraOperationStatus.OPERATION_EMERGENCY_RECORDING_PROGRESS:
                            LogUtils.d(TAG, "onFunctionValueChanged for DVR_FUNC_CAMERA_OPERATION_STATUS, functionValue:OPERATION_EMERGENCY_RECORDING_PROGRESS");
                            for (IOperateResultsWatcher item : mOperateResultWatchers) {
                                item.onDvrEmergencyRecordInProgress();
                            }
                            break;
                        case IDvr.CameraOperationStatus.OPERATION_EMERGENCY_RECORDING_SUCCEED:
                            LogUtils.d(TAG, "onFunctionValueChanged for DVR_FUNC_CAMERA_OPERATION_STATUS, functionValue:OPERATION_EMERGENCY_RECORDING_SUCCEED");
                            for (IOperateResultsWatcher item : mOperateResultWatchers) {
                                item.onDvrEmergencyRecordSuccess();
                            }
                            break;
                        case IDvr.CameraOperationStatus.OPERATION_EMERGENCY_RECORDING_FAILED:
                            LogUtils.d(TAG, "onFunctionValueChanged for DVR_FUNC_CAMERA_OPERATION_STATUS, functionValue:OPERATION_EMERGENCY_RECORDING_FAILED");
                            for (IOperateResultsWatcher item : mOperateResultWatchers) {
                                item.onDvrEmergencyRecordFail();
                            }
                            break;
                        default:
                            LogUtils.w(TAG, "onFunctionValueChanged for DVR_FUNC_CAMERA_OPERATION_STATUS, invalid functionValue:" + functionValue);
                            break;
                    }
                    break;
                case IDvr.DVR_FUNC_CURRENT_STATUS:
                    if (mIsDvrEmergencyRecording && functionValue != IDvr.DvrStates.DVR_STATE_EMERGENCY_RECORDING) {
                        LogUtils.d(TAG, "onFunctionValueChanged for DVR_FUNC_CURRENT_STATUS, functionValue:" + functionValue + ", not emergency_status and last status is emergency_status, callback emergency end!");
                        for (IDvrStateWatcher item : mDvrStateWatchers) {
                            item.onDvrStateEmergencyRecordEnd();
                        }
                    }
                    switch (functionValue) {
                        case IDvr.DvrStates.DVR_STATE_INITIALIZING:
                            LogUtils.d(TAG, "onFunctionValueChanged for DVR_FUNC_CURRENT_STATUS, functionValue:DVR_STATE_INITIALIZING");
                            for (IDvrStateWatcher item : mDvrStateWatchers) {
                                item.onDvrStateInitializing();
                            }
                            break;
                        case IDvr.DvrStates.DVR_STATE_CAPTURE_PIC:
                            LogUtils.d(TAG, "onFunctionValueChanged for DVR_FUNC_CURRENT_STATUS, functionValue:DVR_STATE_CAPTURE_PIC");
                            for (IDvrStateWatcher item : mDvrStateWatchers) {
                                item.onDvrStateCapturePic();
                            }
                            break;
                        case IDvr.DvrStates.DVR_STATE_GENERAL_RECORDING:
                            LogUtils.d(TAG, "onFunctionValueChanged for DVR_FUNC_CURRENT_STATUS, functionValue:DVR_STATE_GENERAL_RECORDING");
                            mIsDvrGeneralRecording = true;
                            for (IDvrStateWatcher item : mDvrStateWatchers) {
                                item.onDvrStateGeneralRecording();
                            }
                            break;
                        case IDvr.DvrStates.DVR_STATE_PAUSE_RECORDING:
                            LogUtils.d(TAG, "onFunctionValueChanged for DVR_FUNC_CURRENT_STATUS, functionValue:DVR_STATE_PAUSE_RECORDING");
                            mIsDvrGeneralRecording = false;
                            for (IDvrStateWatcher item : mDvrStateWatchers) {
                                item.onDvrStateGeneralRecordPause();
                            }
                            break;
                        case IDvr.DvrStates.DVR_STATE_EMERGENCY_RECORDING:
                            LogUtils.d(TAG, "onFunctionValueChanged for DVR_FUNC_CURRENT_STATUS, functionValue:DVR_STATE_EMERGENCY_RECORDING");
                            mIsDvrEmergencyRecording = true;
                            for (IDvrStateWatcher item : mDvrStateWatchers) {
                                item.onDvrStateEmergencyRecording();
                            }
                            break;
                        default:
                            LogUtils.w(TAG, "onFunctionValueChanged for DVR_FUNC_CURRENT_STATUS, invalid functionValue:" + functionValue);
                            break;
                    }
                    break;
                case IDvr.DVR_FUNC_ERROR_STATUS:
                    switch (functionValue) {
                        case IDvr.DvrErrorStates.DVR_STATE_CAMERA_CONNECTION_LOST:
                            LogUtils.d(TAG, "onFunctionValueChanged for DVR_FUNC_ERROR_STATUS, functionValue:DVR_STATE_CAMERA_CONNECTION_LOST");
                            for (IDvrStateWatcher item : mDvrStateWatchers) {
                                item.onDvrStateCameraConnectionLost();
                            }
                            break;
                        case IDvr.DvrErrorStates.DVR_STATE_VIDEO_RECORD_FAILURE:
                            LogUtils.d(TAG, "onFunctionValueChanged for DVR_FUNC_ERROR_STATUS, functionValue:DVR_STATE_VIDEO_RECORD_FAILURE");
                            for (IDvrStateWatcher item : mDvrStateWatchers) {
                                item.onDvrStateVideoRecordFailure();
                            }
                            break;
                        case IDvr.DvrErrorStates.DVR_STATE_NETWORK_ABNORMAL:
                            LogUtils.d(TAG, "onFunctionValueChanged for DVR_FUNC_ERROR_STATUS, functionValue:DVR_STATE_NETWORK_ABNORMAL");
                            for (IDvrStateWatcher item : mDvrStateWatchers) {
                                item.onDvrStateNetworkAbnormal();
                            }
                            break;
                        case IDvr.DvrErrorStates.DVR_STATE_ACCELERATION_SENSOR_ABNORMAL:
                            LogUtils.d(TAG, "onFunctionValueChanged for DVR_FUNC_ERROR_STATUS, functionValue:DVR_STATE_ACCELERATION_SENSOR_ABNORMAL");
                            for (IDvrStateWatcher item : mDvrStateWatchers) {
                                item.onDvrStateAccelerationSensorAbnormal();
                            }
                            break;
                        case IDvr.DvrErrorStates.DVR_STATE_MEMORY_READ_ERROR:
                            LogUtils.d(TAG, "onFunctionValueChanged for DVR_FUNC_ERROR_STATUS, functionValue:DVR_STATE_MEMORY_READ_ERROR");
                            for (IDvrStateWatcher item : mDvrStateWatchers) {
                                item.onDvrStateMemoryReadError();
                            }
                            break;
                        case IDvr.DvrErrorStates.DVR_STATE_MEMORY_WRITE_ERROR:
                            LogUtils.d(TAG, "onFunctionValueChanged for DVR_FUNC_ERROR_STATUS, functionValue:DVR_STATE_MEMORY_WRITE_ERROR");
                            for (IDvrStateWatcher item : mDvrStateWatchers) {
                                item.onDvrStateMemoryWriteError();
                            }
                            break;
                        case IDvr.DvrErrorStates.DVR_STATE_SYSTEM_ERROR:
                            LogUtils.d(TAG, "onFunctionValueChanged for DVR_FUNC_ERROR_STATUS, functionValue:DVR_STATE_SYSTEM_ERROR");
                            for (IDvrStateWatcher item : mDvrStateWatchers) {
                                item.onDvrStateSystemError();
                            }
                            break;
                        case IDvr.DvrErrorStates.DVR_STATE_360_VIEWS_MODULE_ERROR:
                            LogUtils.d(TAG, "onFunctionValueChanged for DVR_FUNC_ERROR_STATUS, functionValue:DVR_STATE_360_VIEWS_MODULE_ERROR");
                            for (IDvrStateWatcher item : mDvrStateWatchers) {
                                item.onDvrState360ViewsModuleError();
                            }
                            break;
                        case IDvr.DvrErrorStates.DVR_STATE_OVER_HEAT:
                            LogUtils.d(TAG, "onFunctionValueChanged for DVR_FUNC_ERROR_STATUS, functionValue:DVR_STATE_OVER_HEAT");
                            for (IDvrStateWatcher item : mDvrStateWatchers) {
                                item.onDvrStateOverHead();
                            }
                            break;
                        case IDvr.DvrErrorStates.DVR_STATE_RESOURCE_OCCUPIED:
                            LogUtils.d(TAG, "onFunctionValueChanged for DVR_FUNC_ERROR_STATUS, functionValue:DVR_STATE_RESOURCE_OCCUPIED");
                            for (IDvrStateWatcher item : mDvrStateWatchers) {
                                item.onDvrStateResourceOccupied();
                            }
                            break;
                        case IDvr.DvrErrorStates.SDCARD_STATUS_POOR_WRITE_PERFORMANCE:
                            LogUtils.d(TAG, "onFunctionValueChanged for DVR_FUNC_ERROR_STATUS, functionValue:SDCARD_STATUS_POOR_WRITE_PERFORMANCE");
                            for (IDvrStateWatcher item : mDvrStateWatchers) {
                                item.onDvrStateSdcardStatusPoorWritePerformance();
                            }
                            break;
                        case IDvr.DvrErrorStates.DVR_STATE_VOLTAGE_ABNORMAL:
                            LogUtils.d(TAG, "onFunctionValueChanged for DVR_FUNC_ERROR_STATUS, functionValue:DVR_STATE_VOLTAGE_ABNORMAL");
                            for (IDvrStateWatcher item : mDvrStateWatchers) {
                                item.onDvrStateVoltageAbnormal();
                            }
                            break;
                        case IDvr.DvrErrorStates.DVR_STATE_UNKNOWN_ERROR:
                            LogUtils.d(TAG, "onFunctionValueChanged for DVR_FUNC_ERROR_STATUS, functionValue:DVR_STATE_UNKNOWN_ERROR");
                            for (IDvrStateWatcher item : mDvrStateWatchers) {
                                item.onDvrStateUnknownError();
                            }
                            break;
                        case IDvr.DvrErrorStates.DVR_STATE_NO_ERROR:
                            LogUtils.d(TAG, "onFunctionValueChanged for DVR_FUNC_ERROR_STATUS, functionValue:DVR_STATE_NO_ERROR");
                            for (IDvrStateWatcher item : mDvrStateWatchers) {
                                item.onDvrNoError();
                            }
                            break;
                        default:
                            LogUtils.w(TAG, "onFunctionValueChanged for DVR_FUNC_ERROR_STATUS, invalid functionValue:" + functionValue);
                            break;
                    }
                    break;
                case IDvr.DVR_FUNC_VIDEO_RESOLUTION:
                    int resolutionIndex = RESOLUTION_MAP.indexOfValue(functionValue);
                    if (resolutionIndex != INVALID_INDEX) {
                        int resolution = RESOLUTION_MAP.keyAt(resolutionIndex);
                        LogUtils.d(TAG, "onFunctionValueChanged for DVR_FUNC_VIDEO_RESOLUTION, functionValue:" + getFunctionResolutionStr(functionValue) + ", value:" + resolution);
                        for (IDvrAPI.IDvrConfigWatcher item : mDvrConfigWatchers) {
                            item.onDvrGeneralRecordResolutionChanged(resolution);
                        }
                    } else {
                        LogUtils.w(TAG, "onFunctionValueChanged for DVR_FUNC_VIDEO_RESOLUTION, invalid functionValue:" + functionValue);
                    }
                    break;
                case IDvr.DVR_FUNC_SDCARD_FORMAT_STATUS:
                    switch (functionValue) {
                        case IDvr.OperationStatus.OPERATION_STATUS_UNKNOWN:
                            LogUtils.d(TAG, "onFunctionValueChanged for DVR_FUNC_SDCARD_FORMAT_STATUS, functionValue:OPERATION_STATUS_UNKNOWN");
                            for (IOperateResultsWatcher item : mOperateResultWatchers) {
                                item.onOperationUnknown();
                            }
                            break;
                        case IDvr.OperationStatus.OPERATION_STATUS_PROGRESS:
                            LogUtils.d(TAG, "onFunctionValueChanged for DVR_FUNC_SDCARD_FORMAT_STATUS, functionValue:OPERATION_STATUS_PROGRESS");
                            for (IOperateResultsWatcher item : mOperateResultWatchers) {
                                item.onSdcardFormatInProgress();
                            }
                            break;
                        case IDvr.OperationStatus.OPERATION_STATUS_SUCCEED:
                            LogUtils.d(TAG, "onFunctionValueChanged for DVR_FUNC_SDCARD_FORMAT_STATUS, functionValue:OPERATION_STATUS_SUCCEED");
                            for (IOperateResultsWatcher item : mOperateResultWatchers) {
                                item.onSdcardFormatSuccess();
                            }
                            break;
                        case IDvr.OperationStatus.OPERATION_STATUS_FAILED:
                            LogUtils.d(TAG, "onFunctionValueChanged for DVR_FUNC_SDCARD_FORMAT_STATUS, functionValue:OPERATION_STATUS_FAILED");
                            for (IOperateResultsWatcher item : mOperateResultWatchers) {
                                item.onSdcardFormatFail();
                            }
                            break;
                        default:
                            LogUtils.w(TAG, "onFunctionValueChanged for DVR_FUNC_SDCARD_FORMAT_STATUS, invalid functionValue:" + functionValue);
                            break;
                    }
                    break;
                case IDvr.DVR_FUNC_FACTORY_RESET_STATUS:
                    switch (functionValue) {
                        case IDvr.OperationStatus.OPERATION_STATUS_UNKNOWN:
                            LogUtils.d(TAG, "onFunctionValueChanged for DVR_FUNC_FACTORY_RESET_STATUS, functionValue:OPERATION_STATUS_UNKNOWN");
                            for (IOperateResultsWatcher item : mOperateResultWatchers) {
                                item.onOperationUnknown();
                            }
                            break;
                        case IDvr.OperationStatus.OPERATION_STATUS_PROGRESS:
                            LogUtils.d(TAG, "onFunctionValueChanged for DVR_FUNC_FACTORY_RESET_STATUS, functionValue:OPERATION_STATUS_PROGRESS");
                            for (IOperateResultsWatcher item : mOperateResultWatchers) {
                                item.onFactoryResetInProgress();
                            }
                            break;
                        case IDvr.OperationStatus.OPERATION_STATUS_SUCCEED:
                            LogUtils.d(TAG, "onFunctionValueChanged for DVR_FUNC_FACTORY_RESET_STATUS, functionValue:OPERATION_STATUS_SUCCEED");
                            for (IOperateResultsWatcher item : mOperateResultWatchers) {
                                item.onFactoryResetSuccess();
                            }
                            break;
                        case IDvr.OperationStatus.OPERATION_STATUS_FAILED:
                            LogUtils.d(TAG, "onFunctionValueChanged for DVR_FUNC_FACTORY_RESET_STATUS, functionValue:OPERATION_STATUS_FAILED");
                            for (IOperateResultsWatcher item : mOperateResultWatchers) {
                                item.onFactoryResetFail();
                            }
                            break;
                        default:
                            LogUtils.w(TAG, "onFunctionValueChanged for DVR_FUNC_FACTORY_RESET_STATUS, invalid functionValue:" + functionValue);
                            break;
                    }
                    break;
                case IDvr.DVR_FUNC_SDCARD_USED_PERCENTAGE:
                    LogUtils.d(TAG, "onFunctionValueChanged for DVR_FUNC_SDCARD_USED_PERCENTAGE, functionValue:" + functionValue);
                    for (IDvrAPI.IDvrConfigWatcher item : mDvrConfigWatchers) {
                        item.onDvrSdcardUsedPercentageChanged(functionValue);
                    }
                    break;
                case IDvr.DVR_FUNC_SDCARD_STATUS:
                    switch (functionValue) {
                        case IDvr.SDCardStatus.SDCARD_STATE_UNKNOWN:
                            LogUtils.d(TAG, "onFunctionValueChanged for DVR_FUNC_SDCARD_STATUS, functionValue:SDCARD_STATE_UNKNOWN");
                            for (ISdcardStateWatcher item : mSdcardStateWatchers) {
                                item.onSdcardStateUnknown();
                            }
                            break;
                        case IDvr.SDCardStatus.SDCARD_STATUS_NORMAL:
                            LogUtils.d(TAG, "onFunctionValueChanged for DVR_FUNC_SDCARD_STATUS, functionValue:SDCARD_STATUS_NORMAL");
                            for (ISdcardStateWatcher item : mSdcardStateWatchers) {
                                item.onSdcardStateNormal();
                            }
                            break;
                        case IDvr.SDCardStatus.SDCARD_STATUS_NO_SDCARD:
                            LogUtils.d(TAG, "onFunctionValueChanged for DVR_FUNC_SDCARD_STATUS, functionValue:SDCARD_STATUS_NO_SDCARD");
                            for (ISdcardStateWatcher item : mSdcardStateWatchers) {
                                item.onSdcardStateNoSdcard();
                            }
                            break;
                        case IDvr.SDCardStatus.SDCARD_STATUS_ERROR:
                            LogUtils.d(TAG, "onFunctionValueChanged for DVR_FUNC_SDCARD_STATUS, functionValue:SDCARD_STATUS_ERROR");
                            for (ISdcardStateWatcher item : mSdcardStateWatchers) {
                                item.onSdcardStateError();
                            }
                            break;
                        case IDvr.SDCardStatus.SDCARD_STATUS_INITIALIZE_FAIL:
                            LogUtils.d(TAG, "onFunctionValueChanged for DVR_FUNC_SDCARD_STATUS, functionValue:SDCARD_STATUS_INITIALIZE_FAIL");
                            for (ISdcardStateWatcher item : mSdcardStateWatchers) {
                                item.onSdcardStateInitializeFail();
                            }
                            break;
                        case IDvr.SDCardStatus.SDCARD_STATUS_POOR_WRITE_PERFORMANCE:
                            LogUtils.d(TAG, "onFunctionValueChanged for DVR_FUNC_SDCARD_STATUS, functionValue:SDCARD_STATUS_POOR_WRITE_PERFORMANCE");
                            for (ISdcardStateWatcher item : mSdcardStateWatchers) {
                                item.onSdcardStatePoorWritePerformance();
                            }
                            break;
                        case IDvr.SDCardStatus.SDCARD_STATUS_NOT_FORMATTED:
                            LogUtils.d(TAG, "onFunctionValueChanged for DVR_FUNC_SDCARD_STATUS, functionValue:SDCARD_STATUS_NOT_FORMATTED");
                            for (ISdcardStateWatcher item : mSdcardStateWatchers) {
                                item.onSdcardStateNotFormatted();
                            }
                            break;
                        case IDvr.SDCardStatus.SDCARD_STATUS_FORMATTING:
                            LogUtils.d(TAG, "onFunctionValueChanged for DVR_FUNC_SDCARD_STATUS, functionValue:SDCARD_STATUS_FORMATTING");
                            for (ISdcardStateWatcher item : mSdcardStateWatchers) {
                                item.onSdcardStateFormatting();
                            }
                            break;
                        case IDvr.SDCardStatus.SDCARD_STATUS_NO_SPACE:
                            LogUtils.d(TAG, "onFunctionValueChanged for DVR_FUNC_SDCARD_STATUS, functionValue:SDCARD_STATUS_NO_SPACE");
                            for (ISdcardStateWatcher item : mSdcardStateWatchers) {
                                item.onSdcardStateNoSpace();
                            }
                            break;
                        case IDvr.SDCardStatus.SDCARD_STATUS_WRITE_FAIL:
                            LogUtils.d(TAG, "onFunctionValueChanged for DVR_FUNC_SDCARD_STATUS, functionValue:SDCARD_STATUS_WRITE_FAIL");
                            for (ISdcardStateWatcher item : mSdcardStateWatchers) {
                                item.onSdcardStateWriteFail();
                            }
                            break;
                        case IDvr.SDCardStatus.SDCARD_STATUS_SDCARD_INCOMPATIBLE:
                            LogUtils.d(TAG, "onFunctionValueChanged for DVR_FUNC_SDCARD_STATUS, functionValue:SDCARD_STATUS_SDCARD_INCOMPATIBLE");
                            for (ISdcardStateWatcher item : mSdcardStateWatchers) {
                                item.onSdcardStateSdcardIncompatible();
                            }
                            break;
                        case IDvr.SDCardStatus.SDCARD_STATUS_EMERGENCY_AREA_OVER_THRESHOLD:
                            LogUtils.d(TAG, "onFunctionValueChanged for DVR_FUNC_SDCARD_STATUS, functionValue:SDCARD_STATUS_EMERGENCY_AREA_OVER_THRESHOLD");
                            for (ISdcardStateWatcher item : mSdcardStateWatchers) {
                                item.onSdcardStateEmergencyAreaOverThreshold();
                            }
                            break;
                        case IDvr.SDCardStatus.SDCARD_STATUS_PRIVATE_FILES_TAKE_TOO_MUCH_SPACE:
                            LogUtils.d(TAG, "onFunctionValueChanged for DVR_FUNC_SDCARD_STATUS, functionValue:SDCARD_STATUS_PRIVATE_FILES_TAKE_TOO_MUCH_SPACE");
                            for (ISdcardStateWatcher item : mSdcardStateWatchers) {
                                item.onSdcardStatePrivateFilesTakeTooMuchSpace();
                            }
                            break;
                        case IDvr.SDCardStatus.SDCARD_STATUS_EMERGENCY_VIDEO_PARTITION_FULL:
                            LogUtils.d(TAG, "onFunctionValueChanged for DVR_FUNC_SDCARD_STATUS, functionValue:SDCARD_STATUS_EMERGENCY_VIDEO_PARTITION_FULL");
                            for (ISdcardStateWatcher item : mSdcardStateWatchers) {
                                item.onSdCardStateEmergencyVideoPartitionFull();
                            }
                            break;
                        case IDvr.SDCardStatus.SDCARD_STATUS_PHOTO_PARTITION_FULL:
                            LogUtils.d(TAG, "onFunctionValueChanged for DVR_FUNC_SDCARD_STATUS, functionValue:SDCARD_STATUS_PHOTO_PARTITION_FULL");
                            for (ISdcardStateWatcher item : mSdcardStateWatchers) {
                                item.onSdCardStatePhotoPartitionFull();
                            }
                            break;
                        default:
                            LogUtils.w(TAG, "onFunctionValueChanged for DVR_FUNC_SDCARD_STATUS, invalid functionValue:" + functionValue);
                            break;
                    }
                    break;
                case IDvr.DVR_FUNC_EMMC_STATE:
                    switch (functionValue) {
                        case IDvr.DvrEmmcState.DVREMMC_STATUS_NORMAL:
                            LogUtils.d(TAG, "onFunctionValueChanged for DVR_FUNC_EMMC_STATE, functionValue:DVREMMC_STATUS_NORMAL");
                            for (IDvrStateWatcher item : mDvrStateWatchers) {
                                item.onDvrEMMCStateNormal();
                            }
                            break;
                        case IDvr.DvrEmmcState.DVREMMC_STATUS_ERROR:
                            LogUtils.d(TAG, "onFunctionValueChanged for DVR_FUNC_EMMC_STATE, functionValue:DVREMMC_STATUS_ERROR");
                            for (IDvrStateWatcher item : mDvrStateWatchers) {
                                item.onDvrEMMCStateError();
                            }
                            break;
                        default:
                            LogUtils.w(TAG, "onFunctionValueChanged for DVR_FUNC_EMMC_STATE, invalid functionValue:" + functionValue);
                        break;
                    }
                    break;
                case IDvr.DVR_FUNC_WAKEUP_ETHERNET:
                    LogUtils.d(TAG, "onFunctionValueChanged for DVR_FUNC_WAKEUP_ETHERNET, functionValue:" + functionValue);
                    break;
                default:
                    break;
            }
        }
    };

    private final List<IDvrAPI.IDvrConfigWatcher> mDvrConfigWatchers = new ArrayList<>();
    private final List<IDvrStateWatcher> mDvrStateWatchers = new ArrayList<>();
    private final List<ISdcardStateWatcher> mSdcardStateWatchers = new ArrayList<>();
    private final List<IOperateResultsWatcher> mOperateResultWatchers = new ArrayList<>();

    private boolean hasRegisterFunctionWatcher = false;

    @Override
    public boolean isDvrDeviceSupported() {
        final int functionId = IDvr.DVR_FUNC_CURRENT_STATUS;
        return isFunctionSupported(functionId) && isFunctionActive(functionId);
    }

    @Override
    public int getDvrGeneralRecordResolution() {
        final int functionId = IDvr.DVR_FUNC_VIDEO_RESOLUTION;
        if (!isFunctionSupported(functionId)) {
            LogUtils.d(TAG, "getDvrGeneralRecordResolution, functionId:DVR_FUNC_VIDEO_RESOLUTION, not supported");
        } else if (!isFunctionActive(functionId)) {
            LogUtils.d(TAG, "getDvrGeneralRecordResolution, functionId:DVR_FUNC_VIDEO_RESOLUTION, not active");
        } else {
            int functionResolution = AospCarManager.get().getCarFunctionProxy().getFunctionValue(functionId);
            LogUtils.d(TAG, "getDvrGeneralRecordResolution, functionId:DVR_FUNC_VIDEO_RESOLUTION, value:" + functionResolution);
            int index = RESOLUTION_MAP.indexOfValue(functionResolution);
            if (index != INVALID_INDEX) {
                return RESOLUTION_MAP.keyAt(index);
            }
        }
        return DEFAULT_LOOP_RECORD_RESOLUTION;
    }

    @Override
    public int getDvrGeneralRecordDuration() {
        final int functionId = IDvr.DVR_FUNC_GENERAL_RECORDING_DURATION;
        if (!isFunctionSupported(functionId)) {
            LogUtils.d(TAG, "getDvrGeneralRecordDuration, functionId:DVR_FUNC_GENERAL_RECORDING_DURATION, not supported");
        } else if (!isFunctionActive(functionId)) {
            LogUtils.d(TAG, "getDvrGeneralRecordDuration, functionId:DVR_FUNC_GENERAL_RECORDING_DURATION, not active");
        } else {
            int functionDuration = AospCarManager.get().getCarFunctionProxy().getFunctionValue(functionId);
            LogUtils.d(TAG, "getDvrGeneralRecordDuration, functionId:DVR_FUNC_GENERAL_RECORDING_DURATION, value:" + functionDuration);
            int index = DURATION_MAP.indexOfValue(functionDuration);
            if (index != INVALID_INDEX) {
                return DURATION_MAP.keyAt(index);
            }
            return INVALID_INDEX;
        }
        return DEFAULT_LOOP_RECORD_DURATION;
    }

    @Override
    public boolean getDvrGeneralRecordMicMute() {
        boolean result = false;
        final int functionId = IDvr.DVR_FUNC_GENERAL_RECORDING_MIC_MUTE;
        if (!isFunctionSupported(functionId)) {
            LogUtils.d(TAG, "getDvrGeneralRecordMicMute, functionId:DVR_FUNC_GENERAL_RECORDING_MIC_MUTE, but not supported");
        } else if (!isFunctionActive(functionId)) {
            LogUtils.d(TAG, "getDvrGeneralRecordMicMute, functionId:DVR_FUNC_GENERAL_RECORDING_MIC_MUTE, but not active");
        } else {
            int functionValue = AospCarManager.get().getCarFunctionProxy().getFunctionValue(functionId);
            result = (MIC_MUTE_MAP.get(true) == functionValue);
            LogUtils.d(TAG, "getDvrGeneralRecordMicMute, functionId:DVR_FUNC_GENERAL_RECORDING_MIC_MUTE, value:" + functionValue + ", result:" + result);
        }
        return result;
    }

    @Override
    public boolean setDvrGeneralRecordResolution(@Constants.LoopRecordResolution int resolution) {
        boolean result = false;
        final int functionId = IDvr.DVR_FUNC_VIDEO_RESOLUTION;
        if (!isFunctionSupported(functionId)) {
            LogUtils.d(TAG, "setDvrGeneralRecordResolution, functionId:DVR_FUNC_VIDEO_RESOLUTION, not supported");
        } else if (!isFunctionActive(functionId)) {
            LogUtils.d(TAG, "setDvrGeneralRecordResolution, functionId:DVR_FUNC_VIDEO_RESOLUTION, not active");
        } else {
            int functionResolution = RESOLUTION_MAP.get(resolution, INVALID_VALUE);
            if (functionResolution != INVALID_VALUE) {
                result = AospCarManager.get().getCarFunctionProxy().setFunctionValue(functionId, functionResolution);
                LogUtils.d(TAG, "setDvrGeneralRecordResolution, functionId:DVR_FUNC_VIDEO_RESOLUTION, value:" + getFunctionResolutionStr(functionResolution) + ", result:" + result);
            } else {
                LogUtils.w(TAG, "setDvrGeneralRecordResolution, not supported for resolution:" + resolution);
            }
        }
        return result;
    }

    @Override
    public boolean setDvrGeneralRecordDuration(@Constants.LoopRecordDuration int duration) {
        boolean result = false;
        final int functionId = IDvr.DVR_FUNC_GENERAL_RECORDING_DURATION;
        if (!isFunctionSupported(functionId)) {
            LogUtils.d(TAG, "setDvrGeneralRecordDuration, functionId:DVR_FUNC_GENERAL_RECORDING_DURATION, not supported");
        } else if (!isFunctionActive(functionId)) {
            LogUtils.d(TAG, "setDvrGeneralRecordDuration, functionId:DVR_FUNC_GENERAL_RECORDING_DURATION, not active");
        } else {
            int functionDuration = DURATION_MAP.get(duration, INVALID_VALUE);
            if (functionDuration != INVALID_VALUE) {
                result = AospCarManager.get().getCarFunctionProxy().setFunctionValue(functionId, functionDuration);
                LogUtils.d(TAG, "setDvrGeneralRecordDuration, functionId:DVR_FUNC_GENERAL_RECORDING_DURATION, value:" + getFunctionDurationStr(functionDuration) + ", result:" + result);
            } else {
                LogUtils.w(TAG, "setDvrGeneralRecordDuration, not supported for duration:" + duration);
            }
        }
        return result;
    }

    @Override
    public boolean setDvrGeneralRecordMicMute(boolean mute) {
        boolean result = false;
        final int functionId = IDvr.DVR_FUNC_GENERAL_RECORDING_MIC_MUTE;
        if (!isFunctionSupported(functionId)) {
            LogUtils.d(TAG, "setDvrGeneralRecordMicMute, functionId:DVR_FUNC_GENERAL_RECORDING_MIC_MUTE, value:" + mute + ", but not supported");
        } else if (!isFunctionActive(functionId)) {
            LogUtils.d(TAG, "setDvrGeneralRecordMicMute, functionId:DVR_FUNC_GENERAL_RECORDING_MIC_MUTE, value:" + mute + ", but not active");
        } else {
            int functionValue = MIC_MUTE_MAP.get(mute);
            result = AospCarManager.get().getCarFunctionProxy().setFunctionValue(functionId, functionValue);
            LogUtils.d(TAG, "setDvrGeneralRecordMicMute, functionId:DVR_FUNC_GENERAL_RECORDING_MIC_MUTE, functionValue:" + functionValue + ", mute:" + mute + ", result:" + result);
        }
        return result;
    }

    @Override
    public boolean registerDvrConfigWatcher(IDvrAPI.IDvrConfigWatcher watcher) {
        return watcher != null && !mDvrConfigWatchers.contains(watcher) && mDvrConfigWatchers.add(watcher);
    }

    @Override
    public void unregisterDvrConfigWatcher(IDvrAPI.IDvrConfigWatcher watcher) {
        if (watcher != null) {
            mDvrConfigWatchers.remove(watcher);
        }
    }

    @Override
    public int getSdcardUsedPercentage() {
        final int functionId = IDvr.DVR_FUNC_SDCARD_USED_PERCENTAGE;
        if (!isFunctionSupported(functionId)) {
            LogUtils.d(TAG, "getSdcardUsedPercentage, functionId:DVR_FUNC_SDCARD_USED_PERCENTAGE, not supported");
        } else if (!isFunctionActive(functionId)) {
            LogUtils.d(TAG, "getSdcardUsedPercentage, functionId:DVR_FUNC_SDCARD_USED_PERCENTAGE, not active");
        } else {
            int functionValue = AospCarManager.get().getCarFunctionProxy().getFunctionValue(functionId);
            LogUtils.d(TAG, "getSdcardUsedPercentage, functionId:DVR_FUNC_SDCARD_USED_PERCENTAGE, value:" + functionValue);
            return functionValue;
        }
        return INVALID_VALUE;
    }

    @Override
    public void init() {
        if (!hasRegisterFunctionWatcher) {
            boolean result = AospCarManager.get().getCarFunctionProxy().registerFunctionValueWatcher(WATCHER_FUNCTION_IDS, mFunctionValueWatcher);
            LogUtils.d(TAG, "registerFunctionValueWatcher, ids:" + Arrays.toString(WATCHER_FUNCTION_IDS) + ", result:" + result);
            if (result) {
                hasRegisterFunctionWatcher = true;
            }
        }
    }

    @Override
    public void destroy() {
        boolean result = AospCarManager.get().getCarFunctionProxy().unregisterFunctionValueWatcher(mFunctionValueWatcher);
        LogUtils.d(TAG, "unregisterFunctionValueWatcher, ids:" + Arrays.toString(WATCHER_FUNCTION_IDS) + ", result:" + result);
        if (result) {
            hasRegisterFunctionWatcher = false;
        }
    }

    @Override
    public boolean registerDvrStateWatcher(IDvrStateWatcher watcher) {
        return watcher != null && !mDvrStateWatchers.contains(watcher) && mDvrStateWatchers.add(watcher);
    }

    @Override
    public void unregisterDvrStateWatcher(IDvrStateWatcher watcher) {
        if (watcher != null) {
            mDvrStateWatchers.remove(watcher);
        }
    }

    @Override
    public boolean registerSdcardStateWatcher(ISdcardStateWatcher watcher) {
        return watcher != null && !mSdcardStateWatchers.contains(watcher) && mSdcardStateWatchers.add(watcher);
    }

    @Override
    public void unregisterSdcardStateWatcher(ISdcardStateWatcher watcher) {
        if (watcher != null) {
            mSdcardStateWatchers.remove(watcher);
        }
    }

    @Override
    public boolean registerOperateResultsWatcher(IOperateResultsWatcher watcher) {
        return watcher != null && !mOperateResultWatchers.contains(watcher) && mOperateResultWatchers.add(watcher);
    }

    @Override
    public void unregisterOperateResultsWatcher(IOperateResultsWatcher watcher) {
        if (watcher != null) {
            mOperateResultWatchers.remove(watcher);
        }
    }

    @Override
    public boolean openDvr() {
        boolean result = false;
        final int functionId = IDvr.DVR_FUNC_OPEN_EXIT;
        if (!isFunctionSupported(functionId)) {
            LogUtils.w(TAG, "openDvr, but not supported!");
        } else if (!isFunctionActive(functionId)) {
            LogUtils.w(TAG, "openDvr, but not active!");
        } else {
            result = AospCarManager.get().getCarFunctionProxy().setFunctionValue(functionId, ICarFunction.COMMON_VALUE_ON);
            LogUtils.d(TAG, "openDvr, functionId:DVR_FUNC_OPEN_EXIT, value:COMMON_VALUE_ON, result:" + result);
        }
        return result;
    }

    @Override
    public boolean exitDvr() {
        boolean result = false;
        final int functionId = IDvr.DVR_FUNC_OPEN_EXIT;
        if (!isFunctionSupported(functionId)) {
            LogUtils.w(TAG, "exitDvr, but not supported!");
        } else if (!isFunctionActive(functionId)) {
            LogUtils.w(TAG, "exitDvr, but not active!");
        } else {
            result = AospCarManager.get().getCarFunctionProxy().setFunctionValue(functionId, ICarFunction.COMMON_VALUE_OFF);
            LogUtils.d(TAG, "exitDvr, functionId:DVR_FUNC_OPEN_EXIT, value:COMMON_VALUE_OFF, result:" + result);
        }
        return result;
    }

    @Override
    public boolean startGeneralRecord() {
        boolean result = false;
        final int functionId = IDvr.DVR_FUNC_CAMERA_OPERATION;
        if (!isFunctionSupported(functionId)) {
            LogUtils.w(TAG, "startGeneralRecord, but not supported!");
        } else if (!isFunctionActive(functionId)) {
            LogUtils.w(TAG, "startGeneralRecord, but not active!");
        } else {
            result = AospCarManager.get().getCarFunctionProxy().setFunctionValue(functionId, IDvr.DvrOperation.OPERATION_GENERAL_RECORDING);
            LogUtils.d(TAG, "startGeneralRecord, functionId:DVR_FUNC_CAMERA_OPERATION, value:DvrOperation.OPERATION_GENERAL_RECORDING, result:" + result);
        }
        return result;
    }

    @Override
    public boolean startEmergencyRecord() {
        boolean result = false;
        final int functionId = IDvr.DVR_FUNC_CAMERA_OPERATION;
        if (!isFunctionSupported(functionId)) {
            LogUtils.w(TAG, "startEmergencyRecord, but not supported!");
        } else if (!isFunctionActive(functionId)) {
            LogUtils.w(TAG, "startEmergencyRecord, but not active!");
        } else {
            result = AospCarManager.get().getCarFunctionProxy().setFunctionValue(functionId, IDvr.DvrOperation.OPERATION_EMERGENCY_RECORDING);
            LogUtils.d(TAG, "startEmergencyRecord, functionId:DVR_FUNC_CAMERA_OPERATION, value:DvrOperation.OPERATION_EMERGENCY_RECORDING, result:" + result);
        }
        return result;
    }

    @Override
    public boolean pauseGeneralRecord() {
        boolean result = false;
        final int functionId = IDvr.DVR_FUNC_CAMERA_OPERATION;
        if (!isFunctionSupported(functionId)) {
            LogUtils.w(TAG, "pauseGeneralRecord, but not supported!");
        } else if (!isFunctionActive(functionId)) {
            LogUtils.w(TAG, "pauseGeneralRecord, but not active!");
        } else {
            result = AospCarManager.get().getCarFunctionProxy().setFunctionValue(functionId, IDvr.DvrOperation.OPERATION_PAUSE_RECORDING);
            LogUtils.d(TAG, "pauseGeneralRecord, functionId:DVR_FUNC_CAMERA_OPERATION, value:DvrOperation.OPERATION_PAUSE_RECORDING, result:" + result);
        }
        return result;
    }

    @Override
    public boolean doCapture() {
        boolean result = false;
        final int functionId = IDvr.DVR_FUNC_CAMERA_OPERATION;
        if (!isFunctionSupported(functionId)) {
            LogUtils.w(TAG, "doCapture, but not supported!");
        } else if (!isFunctionActive(functionId)) {
            LogUtils.w(TAG, "doCapture, but not active!");
        } else {
            result = AospCarManager.get().getCarFunctionProxy().setFunctionValue(functionId, IDvr.DvrOperation.OPERATION_CAPTURE_PIC);
            LogUtils.d(TAG, "doCapture, functionId:DVR_FUNC_CAMERA_OPERATION, value:DvrOperation.OPERATION_CAPTURE_PIC, result:" + result);
        }
        return result;
    }

    @Override
    public boolean doDvrFactoryReset() {
        boolean result = false;
        final int functionId = IDvr.DVR_FUNC_FACTORY_RESET;
        if (!isFunctionSupported(functionId)) {
            LogUtils.w(TAG, "doDvrFactoryReset, but not supported!");
        } else if (!isFunctionActive(functionId)) {
            LogUtils.w(TAG, "doDvrFactoryReset, but not active!");
        } else {
            result = AospCarManager.get().getCarFunctionProxy().setFunctionValue(functionId, ICarFunction.COMMON_VALUE_DEFAULT);
            LogUtils.d(TAG, "doDvrFactoryReset, functionId:DVR_FUNC_FACTORY_RESET, value:COMMON_VALUE_DEFAULT, result:" + result);
        }
        return result;
    }

    @Override
    public boolean doDvrSdcardFormat() {
        boolean result = false;
        final int functionId = IDvr.DVR_FUNC_SDCARD_FORMAT;
        if (!isFunctionSupported(functionId)) {
            LogUtils.w(TAG, "doDvrSdcardFormat, but not supported!");
        } else if (!isFunctionActive(functionId)) {
            LogUtils.w(TAG, "doDvrSdcardFormat, but not active!");
        } else {
            result = AospCarManager.get().getCarFunctionProxy().setFunctionValue(functionId, ICarFunction.COMMON_VALUE_DEFAULT);
            LogUtils.d(TAG, "doDvrSdcardFormat, functionId:DVR_FUNC_SDCARD_FORMAT, value:COMMON_VALUE_DEFAULT, result:" + result);
        }
        return result;
    }

    @Override
    public boolean wakeupEthernet() {
        boolean result = false;
        final int functionId = IDvr.DVR_FUNC_WAKEUP_ETHERNET;
        if (!isFunctionSupported(functionId)) {
            LogUtils.w(TAG, "wakeupEthernet, but not supported!");
        } else if (!isFunctionActive(functionId)) {
            LogUtils.w(TAG, "wakeupEthernet, but not active!");
        } else {
            result = AospCarManager.get().getCarFunctionProxy().setFunctionValue(functionId, ICarFunction.COMMON_VALUE_ON);
            LogUtils.d(TAG, "wakeupEthernet, functionId:DVR_FUNC_WAKEUP_ETHERNET, value:COMMON_VALUE_ON, result:" + result);
        }
        return result;
    }

    @Override
    public boolean isDvrSdcardExists() {
        int sdcardStatus = getSdcardStatus();
        return sdcardStatus != INVALID_INDEX && sdcardStatus != IDvr.SDCardStatus.SDCARD_STATUS_NO_SDCARD;
    }

    @Override
    public boolean isDvrGeneralRecording() {
        int status = getCurrentDvrStatus();
        if (status == IDvr.DvrStates.DVR_STATE_GENERAL_RECORDING) {
            mIsDvrGeneralRecording = true;
        } else if (status == IDvr.DvrStates.DVR_STATE_PAUSE_RECORDING) {
            mIsDvrGeneralRecording = false;
        }
        return mIsDvrGeneralRecording;
    }

    @Override
    public boolean isDvrEmergencyRecording() {
        int status = getCurrentDvrStatus();
        mIsDvrEmergencyRecording = (status == IDvr.DvrStates.DVR_STATE_EMERGENCY_RECORDING);
        return mIsDvrEmergencyRecording;
    }

    @Override
    public String getDvrSoftWareVersion() {
        final int functionId = IDvr.DVR_FUNC_SOFTWARE_VERSION;
        if (!isFunctionSupported(functionId)) {
            LogUtils.d(TAG, "getDvrSoftWareVersion, functionId:DVR_FUNC_SOFTWARE_VERSION, not supported");
        } else if (!isFunctionActive(functionId)) {
            LogUtils.d(TAG, "getDvrSoftWareVersion, functionId:DVR_FUNC_SOFTWARE_VERSION, not active");
        } else {
            int functionValue = AospCarManager.get().getCarFunctionProxy().getFunctionValue(functionId);
            LogUtils.d(TAG, "getDvrSoftWareVersion, functionId:DVR_FUNC_SOFTWARE_VERSION, value:" + functionValue);
            return String.valueOf(functionValue);
        }
        return INVALID_STR_VALUE;
    }

    @Override
    public String getDvrHardWareVersion() {
        final int functionId = IDvr.DVR_FUNC_MODEL_NAME;
        if (!isFunctionSupported(functionId)) {
            LogUtils.d(TAG, "getDvrHardWareVersion, functionId:DVR_FUNC_MODEL_NAME, not supported");
        } else if (!isFunctionActive(functionId)) {
            LogUtils.d(TAG, "getDvrHardWareVersion, functionId:DVR_FUNC_MODEL_NAME, not active");
        } else {
            int functionValue = AospCarManager.get().getCarFunctionProxy().getFunctionValue(functionId);
            LogUtils.d(TAG, "getDvrHardWareVersion, functionId:DVR_FUNC_MODEL_NAME, value:" + functionValue);
            return String.valueOf(functionValue);
        }
        return INVALID_STR_VALUE;
    }

    /**
     * 获取当前Dvr的状态
     * @return
     */
    private int getCurrentDvrStatus() {
        final int functionId = IDvr.DVR_FUNC_CURRENT_STATUS;
        if (!isFunctionSupported(functionId)) {
            LogUtils.d(TAG, "getCurrentDvrStatus, functionId:DVR_FUNC_CURRENT_STATUS, not supported");
        } else if (!isFunctionActive(functionId)) {
            LogUtils.d(TAG, "getCurrentDvrStatus, functionId:DVR_FUNC_CURRENT_STATUS, not active");
        } else {
            int status = AospCarManager.get().getCarFunctionProxy().getFunctionValue(functionId);
            LogUtils.d(TAG, "getCurrentDvrStatus, functionId:DVR_FUNC_CURRENT_STATUS, value:" + status + ", str:" + getFunctionDvrStatusStr(status));
            return status;
        }
        return INVALID_VALUE;
    }

    /**
     * 获取当前sdcard的状态
     * @return
     */
    private int getSdcardStatus() {
        final int functionId = IDvr.DVR_FUNC_SDCARD_STATUS;
        if (!isFunctionSupported(functionId)) {
            LogUtils.d(TAG, "getSdcardStatus, functionId:DVR_FUNC_SDCARD_STATUS, not supported");
        } else if (!isFunctionActive(functionId)) {
            LogUtils.d(TAG, "getSdcardStatus, functionId:DVR_FUNC_SDCARD_STATUS, not active");
        } else {
            int status = AospCarManager.get().getCarFunctionProxy().getFunctionValue(functionId);
            LogUtils.d(TAG, "getSdcardStatus, functionId:DVR_FUNC_SDCARD_STATUS, value:" + status + ", str:" + getFunctionSdcardStatusStr(status));
            return status;
        }
        return INVALID_VALUE;
    }

    /**
     * 返回Dvr状态functionStatus的字符串描述信息
     * @param functionStatus
     * @return
     */
    private String getFunctionDvrStatusStr(int functionStatus) {
        switch (functionStatus) {
            case IDvr.DvrStates.DVR_STATE_INITIALIZING:
                return "DVR_STATE_INITIALIZING";
            case IDvr.DvrStates.DVR_STATE_CAPTURE_PIC:
                return "DVR_STATE_CAPTURE_PIC";
            case IDvr.DvrStates.DVR_STATE_GENERAL_RECORDING:
                return "DVR_STATE_GENERAL_RECORDING";
            case IDvr.DvrStates.DVR_STATE_PAUSE_RECORDING:
                return "DVR_STATE_PAUSE_RECORDING";
            case IDvr.DvrStates.DVR_STATE_EMERGENCY_RECORDING:
                return "DVR_STATE_EMERGENCY_RECORDING";
            default:
                return "unknown";
        }
    }

    /**
     * 返回Sdcard状态functionStatus的字符串描述信息
     * @param functionStatus
     * @return
     */
    private String getFunctionSdcardStatusStr(int functionStatus) {
        switch (functionStatus) {
            case IDvr.SDCardStatus.SDCARD_STATE_UNKNOWN:
                return "SDCARD_STATE_UNKNOWN";
            case IDvr.SDCardStatus.SDCARD_STATUS_NORMAL:
                return "SDCARD_STATUS_NORMAL";
            case IDvr.SDCardStatus.SDCARD_STATUS_NO_SDCARD:
                return "SDCARD_STATUS_NO_SDCARD";
            case IDvr.SDCardStatus.SDCARD_STATUS_ERROR:
                return "SDCARD_STATUS_ERROR";
            case IDvr.SDCardStatus.SDCARD_STATUS_INITIALIZE_FAIL:
                return "SDCARD_STATUS_INITIALIZE_FAIL";
            case IDvr.SDCardStatus.SDCARD_STATUS_POOR_WRITE_PERFORMANCE:
                return "SDCARD_STATUS_POOR_WRITE_PERFORMANCE";
            case IDvr.SDCardStatus.SDCARD_STATUS_NOT_FORMATTED:
                return "SDCARD_STATUS_NOT_FORMATTED";
            case IDvr.SDCardStatus.SDCARD_STATUS_FORMATTING:
                return "SDCARD_STATUS_FORMATTING";
            case IDvr.SDCardStatus.SDCARD_STATUS_NO_SPACE:
                return "SDCARD_STATUS_NO_SPACE";
            case IDvr.SDCardStatus.SDCARD_STATUS_WRITE_FAIL:
                return "SDCARD_STATUS_WRITE_FAIL";
            case IDvr.SDCardStatus.SDCARD_STATUS_SDCARD_INCOMPATIBLE:
                return "SDCARD_STATUS_SDCARD_INCOMPATIBLE";
            case IDvr.SDCardStatus.SDCARD_STATUS_EMERGENCY_AREA_OVER_THRESHOLD:
                return "SDCARD_STATUS_EMERGENCY_AREA_OVER_THRESHOLD";
            case IDvr.SDCardStatus.SDCARD_STATUS_PRIVATE_FILES_TAKE_TOO_MUCH_SPACE:
                return "SDCARD_STATUS_PRIVATE_FILES_TAKE_TOO_MUCH_SPACE";
            case IDvr.SDCardStatus.SDCARD_STATUS_EMERGENCY_VIDEO_PARTITION_FULL:
                return "SDCARD_STATUS_EMERGENCY_VIDEO_PARTITION_FULL";
            case IDvr.SDCardStatus.SDCARD_STATUS_PHOTO_PARTITION_FULL:
                return "SDCARD_STATUS_PHOTO_PARTITION_FULL";
            default:
                return "unknown";
        }
    }

    /**
     * 返回functionDuration的字符串描述信息
     * @param functionDuration
     * @return
     */
    private String getFunctionDurationStr(int functionDuration) {
        switch (functionDuration) {
            case IDvr.RecordingDuration.ONE_MINUTES:
                return "RecordingDuration.ONE_MINUTES";
            case IDvr.RecordingDuration.THREE_MINUTES:
                return "RecordingDuration.THREE_MINUTES";
            case IDvr.RecordingDuration.FIVE_MINUTES:
                return "RecordingDuration.FIVE_MINUTES";
            default:
                return "unknown";
        }
    }

    /**
     * 返回functionResolution的字符串描述信息
     * @param functionResolution
     * @return
     */
    private String getFunctionResolutionStr(int functionResolution) {
        switch (functionResolution) {
            case IDvr.ResolutionType.RESOLUTION_720P_30FPS:
                return "ResolutionType.RESOLUTION_720P_30FPS";
            case IDvr.ResolutionType.RESOLUTION_1080P_30FPS:
                return "ResolutionType.RESOLUTION_1080P_30FPS";
            default:
                return "unknown";
        }
    }

    /**
     * 判断指定functionId是否可以正常使用
     * @param functionId
     * @return
     */
    private boolean isFunctionActive(int functionId) {
        boolean isActive = AospCarManager.get().getCarFunctionProxy().isFunctionActive(functionId);
        LogUtils.d(TAG, "isFunctionActive, functionId:" + functionId + ", isActive:" + isActive);
        return isActive;
    }

    /**
     * 判断指定functionId是否支持
     * @param functionId
     * @return
     */
    private boolean isFunctionSupported(int functionId) {
        boolean isSupported = AospCarManager.get().getCarFunctionProxy().isFunctionSupported(functionId);
        LogUtils.d(TAG, "isFunctionSupported, functionId:" + functionId + ", isSupported:" + isSupported);
        return isSupported;
    }
}
